using System;
using System.Collections.Generic;
using System.Text;

namespace Weazel.Microblaze.Elf
{
  public class ElfProgramHeader : ElfFormatEntity
  {
    #region Enumerations
    public enum P_Type
    {
      PT_NULL    = 0,
      PT_LOAD    = 1,
      PT_DYNAMIC = 2,
      PT_INTERP  = 3,
      PT_NOTE    = 4,
      PT_SHLIB   = 5,
      PT_PHDR    = 6,
      PT_LOPROC  = 0x70000000,
      PT_HIPROC  = 0x7fffffff
    }
    #endregion

    #region Fields
    private P_Type p_type;
    private uint p_offset;
    private uint p_vaddr;
    private uint p_paddr;
    private uint p_filesz;
    private uint p_memsz;
    private uint p_flags;
    private uint p_align;
    private byte[] content;

    #endregion

    #region Properties
    public P_Type P_type
    {
      get { return p_type; }     
    }
    public uint P_offset
    {
      get { return p_offset; }     
    }
    public uint P_vaddr
    {
      get { return p_vaddr; }     
    }
    public uint P_paddr
    {
      get { return p_paddr; }     
    }
    public uint P_filesz
    {
      get { return p_filesz; }     
    }
    public uint P_memsz
    {
      get { return p_memsz; }     
    }
    public uint P_flags
    {
      get { return p_flags; }     
    }
    public uint P_align
    {
      get { return p_align; }     
    }
    public byte[] Content
    {
      get { return content; }     
    }
    #endregion

    public ElfProgramHeader(ElfFile elfFile)
      : base(elfFile)
    {
    }

    public void Read()
    {
      this.p_type = (P_Type)ReadElf32Word(ElfFile.Reader);
      this.p_offset = ReadElf32Off(ElfFile.Reader);
      this.p_vaddr = ReadElf32Addr(ElfFile.Reader);
      this.p_paddr = ReadElf32Addr(ElfFile.Reader);
      this.p_filesz = ReadElf32Word(ElfFile.Reader);
      this.p_memsz = ReadElf32Word(ElfFile.Reader);
      this.p_flags = ReadElf32Word(ElfFile.Reader);
      this.p_align = ReadElf32Word(ElfFile.Reader);

      // save current position
      long position = ElfFile.Reader.BaseStream.Position;

      // set to position of section content
      ElfFile.Reader.BaseStream.Seek(p_offset, 0);

      // read the content
      content = ElfFile.Reader.ReadBytes((int)p_filesz);

      // restore the stream position
      ElfFile.Reader.BaseStream.Seek(position, 0);
    }

    public override string ToString()
    {
      StringBuilder str = new StringBuilder();

      str.AppendFormat("p_type   : {0} \n", this.p_type);
      str.AppendFormat("p_offset : 0x{0:X} \n", this.p_offset);
      str.AppendFormat("p_vaddr  : 0x{0:X} \n", this.p_vaddr);
      str.AppendFormat("p_paddr  : 0x{0:X} \n", this.p_paddr);
      str.AppendFormat("p_filesz : 0x{0:X} \n", this.p_filesz);
      str.AppendFormat("p_memsz  : 0x{0:X} \n", this.p_memsz);
      str.AppendFormat("p_flags  : 0x{0:X} \n", this.p_flags);
      str.AppendFormat("p_align  : 0x{0:X} \n", this.p_align);

      return str.ToString();
    }
  }
}
